package com.piece.core.framework.util.string;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * 二维码工具类
 */
@Slf4j
public class QrcodeUtil {

    /**
     * 创建二维码
     *
     * @param outputStream  输出流
     * @param contents      内容
     * @param width         宽
     * @param height        高
     */
    public static void encode(OutputStream outputStream, String contents, int width, int height) throws IOException {
        encode(outputStream, contents, BarcodeFormat.QR_CODE, 1, "png", width, height);
    }

    /**
     * 创建二维码
     *
     * @param outputStream  输出流
     * @param contents      内容
     * @param barcodeFormat BarcodeFormat对象
     * @param margin        边框间距
     * @param format        图片格式，可选[png,jpg,bmp]
     * @param width         宽
     * @param height        高
     */
    public static void encode(OutputStream outputStream, String contents, BarcodeFormat barcodeFormat, Integer margin, String format, int width, int height) throws IOException {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        if (margin != 0) {
            hints.put(EncodeHintType.MARGIN, margin);
        }
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

        try {
            BitMatrix bitMatrix = (new MultiFormatWriter()).encode(contents, barcodeFormat, width, height, hints);
            MatrixToImageWriter.writeToStream(bitMatrix, format, outputStream);
        } catch (Exception e) {
            log.error("创建二维码异常：{}", e.getMessage());
        } finally {
            if (null != outputStream) {
                outputStream.close();
            }
        }
    }

    /**
     * 创建二维码
     *
     * @param contents      内容
     * @param width         宽
     * @param height        高
     */
    public static byte[] encode(String contents, int width, int height) throws IOException {
        return encode(contents, BarcodeFormat.QR_CODE, 1, "png", width, height);
    }

    /**
     * 创建二维码文件
     *
     * @param contents        内容
     * @param barcodeFormat   BarcodeFormat对象
     * @param format          图片格式，可选[png,jpg,bmp]
     * @param width           宽
     * @param height          高
     * @param margin          边框间距px
     */
    public static byte[] encode(String contents, BarcodeFormat barcodeFormat, Integer margin, String format, int width, int height) {
        BufferedImage bufImg;
        ByteArrayOutputStream os = null;
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.MARGIN, margin);
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

        try {
            BitMatrix bitMatrix = (new MultiFormatWriter()).encode(contents, barcodeFormat, width, height, hints);
            MatrixToImageConfig config = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
            bufImg = MatrixToImageWriter.toBufferedImage(bitMatrix, config);
            os = new ByteArrayOutputStream();
            ImageIO.write(bufImg, format, os);
            return os.toByteArray();
        } catch (Exception e) {
            log.error("创建二维码异常：{}", e.getMessage());
            return null;
        } finally {
            if (null != os) {
                try {
                    os.close();
                    os = null;
                } catch (IOException e) {}
            }
        }
    }

    /**
     * 保存二维码文件
     *
     * @param contents        内容
     * @param barcodeFormat   BarcodeFormat对象
     * @param format          图片格式，可选[png,jpg,bmp]
     * @param width           宽
     * @param height          高
     * @param margin          边框间距px
     * @param saveImgFilePath 存储图片的完整位置，包含文件名
     */
    public static boolean encode(String contents, BarcodeFormat barcodeFormat, Integer margin,
                                 ErrorCorrectionLevel errorLevel, String format, int width, int height, String saveImgFilePath) {
        boolean bool = false;
        BufferedImage bufImg;
        Map<EncodeHintType, Object> hints = new HashMap<>();
        // 指定纠错等级
        hints.put(EncodeHintType.ERROR_CORRECTION, errorLevel);
        hints.put(EncodeHintType.MARGIN, margin);
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, barcodeFormat, width, height, hints);
            MatrixToImageConfig config = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
            bufImg = MatrixToImageWriter.toBufferedImage(bitMatrix, config);
            bool = ImageIO.write(bufImg, format, new File(saveImgFilePath));
        } catch (Exception e) {
            log.error("创建二维码异常：{}", e.getMessage());
        }
        return bool;
    }

    /**
     * 解析二维码图片
     */
    public static String decode(InputStream inputStream) {
        String retStr = "";
        try {
            BufferedImage bufferedImage = ImageIO.read(inputStream);
            LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
            Binarizer binarizer = new HybridBinarizer(source);
            BinaryBitmap bitmap = new BinaryBitmap(binarizer);
            HashMap<DecodeHintType, Object> hintTypeObjectHashMap = new HashMap<>();
            hintTypeObjectHashMap.put(DecodeHintType.CHARACTER_SET, "UTF-8");
            Result result = new MultiFormatReader().decode(bitmap, hintTypeObjectHashMap);
            retStr = result.getText();
        } catch (Exception e) {
            log.error("读取二维码信息异常：{}", e.getMessage());
        }
        return retStr;
    }
}
